home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 7: Sunsite
/
Linux Cubed Series 7 - Sunsite Vol 1.iso
/
system
/
admin
/
linuxcon.000
/
linuxcon
/
linuxconf-1.6
/
netconf
/
ipfwrule.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-08-03
|
12KB
|
527 lines
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/icmp.h>
#include <linux/if.h>
#include <linux/ip_fw.h>
#include <limits.h>
#include <netdb.h>
#include "netconf.h"
#include "internal.h"
#include "firewall.h"
#include "../dialog/dialog.h"
#include "../misc/misc.h"
#include "../userconf/userconf.h"
#include "../paths.h"
#include "netconf.m"
#ifndef IP_FW_POLICY_IN
/* These are just here so it compiles */
#define IP_FW_F_MASQ 0
#define IP_FW_APPEND_OUT 1
#define IP_FW_APPEND_IN 2
#define IP_FW_APPEND_FWD 3
#define FIREWAALL_NONE
#endif
NETCONF_HELP_FILE help_ipfw ("firewall");
PROTECTED IPFW_RULE::IPFW_RULE()
{
from.interface.setfrom ("Any");
to.interface.setfrom ("Any");
protocol.setfrom ("all");
/* #Specification: netconf / firewalling / active rule
One rule may be defined and desactivated without erasing it.
This give some flexibility to the administrator to define
complex rules and "comment out" some.
*/
active = 1;
}
/*
Extract a number from a buffer.
The number may be enclosed in double quote.
*/
static const char *firewall_extract (const char *buf, char &val)
{
SSTRING s;
buf = str_extract (buf,s);
val = s.getval();
return buf;
}
static const char *firewall_extract (const char *buf, IPFW_SRC &s)
{
buf = str_extract (buf,s.host);
buf = str_extract (buf,s.netmask);
buf = str_extract (buf,s.portrange);
buf = str_extract (buf,s.ports);
buf = str_extract (buf,s.interface);
return buf;
}
PROTECTED IPFW_RULE::IPFW_RULE(const char * &buf)
{
buf = firewall_extract (buf,active);
buf = str_extract (buf,protocol);
buf = firewall_extract (buf,from);
buf = firewall_extract (buf,to);
}
PUBLIC IPFW_RULE_FORWARD::IPFW_RULE_FORWARD(const char *buf)
: IPFW_RULE (buf)
{
firewall_extract (buf,masquerade);
}
PUBLIC IPFW_RULE_FORWARD::IPFW_RULE_FORWARD()
{
masquerade = 0;
}
PUBLIC IPFW_RULE_OUTPUT::IPFW_RULE_OUTPUT(const char *buf)
: IPFW_RULE (buf)
{
}
PUBLIC IPFW_RULE_OUTPUT::IPFW_RULE_OUTPUT()
{
}
PUBLIC IPFW_RULE_INPUT::IPFW_RULE_INPUT(const char *buf)
: IPFW_RULE (buf)
{
}
PUBLIC IPFW_RULE_INPUT::IPFW_RULE_INPUT()
{
}
static void firewall_append (char *buf, SSTRING &s)
{
strcat (buf," \"");
strcat (buf,s.get());
strcat (buf,"\"");
}
static void firewall_append (char *buf, int val)
{
char valstr[20];
sprintf (valstr,"%d",val);
strcat (buf," \"");
strcat (buf,valstr);
strcat (buf,"\"");
}
static void firewall_append (char *buf, IPFW_SRC &s)
{
firewall_append (buf,s.host);
firewall_append (buf,s.netmask);
firewall_append (buf,s.portrange);
firewall_append (buf,s.ports);
firewall_append (buf,s.interface);
}
char FIREWALL[] = "firewall";
char FORWARD[] = "forward";
char BLOCK[] = "block";
char OUTPUT[] = "output";
/*
Save one forward line in /etc/conf.linuxconf
*/
PROTECTED void IPFW_RULE::savek(char *buf)
{
buf[0] = '\0';
firewall_append (buf,active);
firewall_append (buf,protocol);
firewall_append (buf,from);
firewall_append (buf,to);
}
/*
Save one forward line in /etc/conf.linuxconf
*/
PUBLIC void IPFW_RULE_FORWARD::save()
{
char buf[2000];
IPFW_RULE::savek(buf);
firewall_append (buf,masquerade);
linuxconf_add (FIREWALL,FORWARD,buf);
}
/*
Save one forward line in /etc/conf.linuxconf
*/
PUBLIC void IPFW_RULE_INPUT::save()
{
char buf[2000];
IPFW_RULE::savek(buf);
linuxconf_add (FIREWALL,BLOCK,buf);
}
/*
Save one output line in /etc/conf.linuxconf
*/
PUBLIC void IPFW_RULE_OUTPUT::save()
{
char buf[2000];
IPFW_RULE::savek(buf);
linuxconf_add (FIREWALL,OUTPUT,buf);
}
/*
Format the minimum information about the rule so it will
be presentable in a menu.
*/
PUBLIC void IPFW_RULE::present (char *buf)
{
sprintf (buf,"[%c] %-4s %4s:%-10s <-> %4s:%-10s"
,active ? 'X' : ' '
,protocol.get()
,from.interface.get()
,from.host.get()
,to.interface.get()
,to.host.get());
}
static void ipfwrule_computemsk (const char ip[], char msk[])
{
int num4[4];
device_aip24 (ip,num4);
if (num4[3] != 0){
strcpy (msk,"255.255.255.255");
}else{
char std_net[20];
device_setstdnetmask(ip,std_net,msk);
}
}
/*
try to convert something into an IP number
Return -1 if it can't.
*/
int ipfwrule_convert (
const char *str, // An IP number, a host name or an interface
// name (eth0)
char ip[],
char msk[]) // Corresponding (computed) netmask
// or extracted from the device
{
int ret = 0;
struct hostent *hent;
struct netent *nent;
IFCONFIG_INFO info;
if (device_validip(str,false)){
strcpy (ip,str);
ipfwrule_computemsk (str,msk);
}else if (ifconfig_getinfo(str,info)!=-1){
// This is a network devices and we must
// pick the IP number since ipfw don't do it.
strcpy (ip,info.ip_addr);
strcpy (msk,info.netmask);
}else if ((hent = gethostbyname(str)) != NULL){
devices_ip2a (hent,ip);
ipfwrule_computemsk (ip,msk);
}else if ((nent = getnetbyname(str)) != NULL){
devices_ip2a (nent,ip);
ipfwrule_computemsk (ip,msk);
}else{
ret = -1;
}
return ret;
}
/*
try to convert something into an IP number
Return -1 if it can't.
*/
static int ipfwrule_convert (
const char *str, // An IP number, a host name or an interface
// name (eth0)
char ip[])
{
char msk[16];
return ipfwrule_convert (str,ip,msk);
}
/*
Return the number of significative bits in the netmask (1's)
Return -1 if any error.
*/
PUBLIC int IPFW_RULE::nbbitmask(IPFW_SRC &f)
{
int ret = f.nbbit_msk;
if (ret == -1){
const char *msk = f.netmask.get();
char std_msk[20];
if (*msk == '\0'){
/* #Specification: firewall / netmask
The netmask is optionnal. It is automacly
compute from the host/network number
*/
char ip[20];
if (ipfwrule_convert(f.host.get(),ip,std_msk)!=-1){
msk = std_msk;
}else{
ret = -1;
}
}
int num4[4];
device_aip24 (msk,num4);
unsigned long nmsk = (num4[0] << 24) | (num4[1] << 16)
| (num4[2] << 8) | num4[3];
unsigned long cmp = 0x80000000l;
int i;
for (i=0; i<32 && (nmsk & cmp) != 0; i++, cmp >>= 1);
ret = i;
f.nbbit_msk = ret;
}
return ret;
}
/*
Return the number of significative bits in the netmask (1's)
This is taken in the from.
*/
PUBLIC int IPFW_RULE::nbbitmask_from()
{
return nbbitmask (from);
}
/*
Return the number of significative bits in the netmask (1's)
This is taken in the "to".
*/
PUBLIC int IPFW_RULE::nbbitmask_to()
{
return nbbitmask (to);
}
/*
Return -1 if abort
Return 0 if accept
Return 1 if delete required
*/
PUBLIC int IPFW_RULE::editk(
DIALOG &dia,
const char *title)
{
dia.newf_chk ("",active,MSG_U(F_RULEACTIVE,"This rule is active"));
int i;
FIELD_COMBO *comb = dia.newf_combo (MSG_U(F_PROTOCOL,"Protocol")
,protocol);
for (i=0; i<4; i++){
static const char *tbproto[]={
"icmp","udp","tcp","all"
};
comb->addopt (tbproto[i]);
}
static const char *tbinter[][2]={
{"Any", MSG_U(F_PACKFROMANY,"Packet come from anywhere") },
{"eth0", MSG_U(F_FIRSTETH,"First ethernet adaptor")},
{"eth1", MSG_U(F_SECOND,"Second")},
{"eth2", MSG_U(F_THIRD,"Third")},
{"eth3", MSG_U(F_FOURTH,"Fourth")},
{"sl0", MSG_U(F_FIRSTSLIP,"First SLIP/CSLIP channel")},
{"sl1", MSG_R(F_SECOND)},
{"ppp0", MSG_U(F_FIRSTPPP,"First PPP channel")},
{"ppp1", MSG_R(F_SECOND)},
};
dia.newf_title ("",MSG_U(F_FROM,"From"));
dia.newf_str (MSG_U(F_HOSTORNET,"Host or Network"),from.host);
dia.newf_str (MSG_U(F_HNETMASK,"Netmask"),from.netmask);
dia.newf_str (MSG_U(F_PORTRANGE,"Port range"),from.portrange);
dia.newf_str (MSG_U(F_OTHERPORTS,"Other ports"),from.ports);
comb = dia.newf_combo (MSG_U(F_INTERFACE,"Interface"),from.interface);
for (i=0; i<9; i++){
comb->addopt (tbinter[i][0],tbinter[i][1]);
}
dia.newf_title ("",MSG_U(F_TO,"To"));
dia.newf_str (MSG_R(F_HOSTORNET),to.host);
dia.newf_str (MSG_R(F_HNETMASK),to.netmask);
dia.newf_str (MSG_R(F_PORTRANGE),to.portrange);
dia.newf_str (MSG_R(F_OTHERPORTS),to.ports);
comb = dia.newf_combo (MSG_R(F_INTERFACE),to.interface);
for (i=0; i<9; i++){
comb->addopt (tbinter[i][0],tbinter[i][1]);
}
int ret = -1;
int nof = 0;
while (1){
MENU_STATUS code = dia.edit (title
,""
,help_ipfw.getpath()
,nof
,MENUBUT_CANCEL|MENUBUT_ACCEPT|MENUBUT_DEL);
if (code == MENU_ESCAPE || code == MENU_CANCEL){
break;
}else if (code == MENU_DEL){
ret = 1;
break;
}else{
ret = 0;
break;
}
}
if (ret != 0) dia.restore();
return ret;
}
/*
Return -1 if abort
*/
PUBLIC int IPFW_RULE_FORWARD::edit()
{
DIALOG dia;
dia.newf_chk ("",masquerade,MSG_U(F_DOMASQUERADE,"Do masquerading"));
return IPFW_RULE::editk (dia,MSG_U(T_FORWARDING,"Firewall forwarding rule"));
}
/*
Return -1 if abort
*/
PUBLIC int IPFW_RULE_OUTPUT::edit()
{
DIALOG dia;
return IPFW_RULE::editk (dia,MSG_U(T_OUTPUT,"Firewall Outputing rule"));
}
/*
Return -1 if abort
*/
PUBLIC int IPFW_RULE_INPUT::edit()
{
DIALOG dia;
return IPFW_RULE::editk (dia,MSG_U(T_INPUTING,"Firewall inputing rule"));
}
PUBLIC int IPFW_RULE::setup(
IPFW_SRC &f,
IPFW_SRC &t,
const char *type,
int doit, // Exec the command ?
SSTRING *collect) // Will contain a copy of the
// command generated
{
int ret = 0;
if (active){
char interbuf[100];
strcpy (interbuf,"0.0.0.0");
if (!f.interface.is_empty()
&& f.interface.cmp("Any")!=0){
/* #Specification: firewall / iface argument
We accept a host name, an IP number or
a network device name (eth0).
*/
char ip[20];
const char *ifacearg = f.interface.get();
if (ipfwrule_convert (ifacearg,ip)!=-1){
sprintf (interbuf,"%s",ip);
}else{
xconf_error (MSG_U(E_IVLDINTER
,"Invalid interface %s for firewalling rule")
,ifacearg);
ret = -1;
}
}
/* #Specification: firewall / forwarding / accept
The firewalling interface support only accepting rule
so far. It is expect to be enough for most firewalls.
Supporting denying and rejecting is not much of a problem
although, Experience will shows us how to do this
without confusing the user...
Comments are welcome.
*/
char fhoststr[PATH_MAX],fhostmsk[16];
ret |= ipfwrule_convert (f.host.get(),fhoststr,fhostmsk);
char thoststr[PATH_MAX],thostmsk[16];
ret |= ipfwrule_convert (t.host.get(),thoststr,thostmsk);
struct ip_fw bf;
if (ipfw_baseinit(interbuf,protocol.get()
,fhoststr,f.netmask.is_empty() ? fhostmsk : f.netmask.get()
,f.portrange.get(),f.ports.get()
,thoststr,t.netmask.is_empty() ? thostmsk : t.netmask.get()
,t.portrange.get(),t.ports.get()
,bf)!=-1){
int command = 0;
if (type[0] == 'm'){
command = IP_FW_APPEND_FWD;
bf.fw_flg |= IP_FW_F_MASQ;
}else if (type[0] == 'f'){
command = IP_FW_APPEND_FWD;
}else if (type[0] == 'o'){
command = IP_FW_APPEND_OUT;
}else if (type[0] == 'b'){
command = IP_FW_APPEND_IN;
}
ret = ipfw_append (doit,collect,command,bf);
}else{
ret = -1;
}
}
return ret;
}
/*
Setup one side of the forwarding rule (from -> to)
*/
PUBLIC int IPFW_RULE_FORWARD::setup_left(int doit, SSTRING *collect)
{
int ret = -1;
if (masquerade){
ret = setup (from,to,"m",doit,collect);
}else{
ret = setup (from,to,"f",doit,collect);
}
return ret;
}
/*
Setup one side of the forwarding rule (to -> from)
*/
PUBLIC int IPFW_RULE_FORWARD::setup_right(int doit, SSTRING *collect)
{
int ret = 0;
if (!masquerade){
ret = setup (to,from,"f",doit,collect);
}
return ret;
}
/*
Setup one side of the forwarding rule (from -> to)
*/
PUBLIC int IPFW_RULE_OUTPUT::setup_left(int doit, SSTRING *collect)
{
return setup (from,to,"o",doit,collect);
}
/*
Setup one side of the forwarding rule (to -> from)
*/
PUBLIC int IPFW_RULE_OUTPUT::setup_right(int doit, SSTRING *collect)
{
return setup (to,from,"o",doit,collect);
}
/*
Setup one side of the blocking rule (from -> to)
*/
PUBLIC int IPFW_RULE_INPUT::setup_left(int doit, SSTRING *collect)
{
return setup (from,to,"b",doit,collect);
}
/*
Setup one side of the blocking rule (to -> from)
*/
PUBLIC int IPFW_RULE_INPUT::setup_right(int doit, SSTRING *collect)
{
return setup (to,from,"b",doit,collect);
}